using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
using DocToolTipLib.Enums;

namespace DocToolTipLib
{
  public class DocToolTip : Form
  {

    #region Attributes
    private string _strControlName;
    private string _strControlType;
    private Control _control;
    private ContextMenuStrip _contextMenuStrip;
    private System.ComponentModel.IContainer components;
    private ToolStripMenuItem hideToolStripMenuItem;
    private ToolStripMenuItem hideAllChildrenToolStripMenuItem;
    private ToolTipProperties _toolTipOptions;
    private List<DocToolTip> _dTTChildrenList;

    FrmDocManager _docManager;

    #endregion Attributes

    #region Constructor
    public DocToolTip(Control control, FrmDocManager docManager)
    {
      InitializeComponent();
      _control = control;
      _strControlName = control.Name;
      _strControlType = control.GetType().Name;
      _strCustomCaption = string.Empty;
      _toolTipOptions = new ToolTipProperties(this);
      _dTTChildrenList = new List<DocToolTip>();
      _docManager = docManager;

      _ptRelativePosition = new Point(0);

    }


    #endregion Constructor

    #region Properties

    private EnumToolTipCaption _eToolTipCaption;
    public EnumToolTipCaption ToolTipCaption
    {
      get { return _eToolTipCaption; }
      set
      {
        _eToolTipCaption = value;
        Refresh();
      }
    }

    private string _strCustomCaption;
    public string CustomCaption
    {
      get { return _strCustomCaption; }
      set
      {
        _strCustomCaption = value;
        Refresh();
      }
    }

    public Type ControlType
    {
      get { return _control.GetType(); }
    }

    public string ControlName
    {
      get { return _control.Name; }
    }

    private Padding _padding = new Padding(3);
    public Padding Padding
    {
      get { return _padding; }
      set
      {
        _padding = value;
        Refresh();
      }

    }

    private bool _isSelected;
    public bool Selected
    {
      get { return _isSelected; }
      set
      {
        _isSelected = value;
        Refresh();
      }
    }

    public ToolTipProperties ToolTipProperties
    {
      get { return _toolTipOptions; }
    }

    public List<DocToolTip> Children
    {
      get { return _dTTChildrenList; }
    }

    private EnumRelativePositionType _eRelativePositionType;
    public EnumRelativePositionType RelativePositionType
    {
      get
      {
        return _eRelativePositionType;
      }
      set
      {
        _eRelativePositionType = value;
        _ptRelativePosition = new Point(0);
        setLocation();
      }
    }

    private Point _ptRelativePosition;
    public Point RelativePosition
    {
      get
      {
        return _ptRelativePosition;
      }
      set
      {
        _ptRelativePosition = value;
      }
    }


    #endregion Properties

    #region Private Methods

    #endregion Private Methods

    #region Public Methods
    public void Relocate()
    {
      Point ptReferenceLocation = calculateReferenceLocation();
      Point ptLocation = _control.PointToScreen(Point.Empty);
      ptLocation = Point.Add(ptLocation, new Size(ptReferenceLocation));
      Location = Point.Add(ptLocation, new Size(_ptRelativePosition));

    }

    public void SetVisibleAllChildren(bool bVisible)
    {
      setVisibleAllChildren(this, bVisible);
    }
    #endregion Public Methods

    #region Overrides

    protected override void OnMouseEnter(EventArgs e)
    {
      Selected = true;
      base.OnMouseEnter(e);
    }

    protected override void OnMouseLeave(EventArgs e)
    {
      Selected = false;
      base.OnMouseLeave(e);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      Font drawFont = this.Font;
      SolidBrush drawBrush = new SolidBrush(this.ForeColor);

      string strLabel = getCaption();
      SizeF size = e.Graphics.MeasureString(strLabel, drawFont);
      this.Size = new Size((int)size.Width + _padding.Size.Width,
                            (int)size.Height + _padding.Size.Height);

      e.Graphics.DrawString(strLabel, drawFont, drawBrush, new PointF(_padding.Left, _padding.Top));
      if (Selected)
      {
        e.Graphics.DrawRectangle(new Pen(drawBrush), 0, 0, Size.Width - 1, Size.Height - 1);
      }
      base.OnPaint(e);
    }

    protected override void OnMove(EventArgs e)
    {
      Point ptReferenceLocation = calculateReferenceLocation();
      Point ptLocation = _control.PointToScreen(Point.Empty);
      ptLocation = Point.Add(ptLocation, new Size(ptReferenceLocation));
      _ptRelativePosition = Point.Subtract(Location, new Size(ptLocation));
      base.OnMove(e);
    }

    #endregion Overrides

    #region Event Handlers

    #endregion Event Handlers




    private Point calculateReferenceLocation()
    {
      Point result = new Point(0, 0);

      switch (_eRelativePositionType)
      {
        case EnumRelativePositionType.Top:
          result = new Point(0, 0);
          break;
        case EnumRelativePositionType.Left:
          result = new Point(-Size.Width, 0);
          break;
        case EnumRelativePositionType.Right:
          result = new Point(_control.Size.Width, 0);
          break;
        case EnumRelativePositionType.Over:
          result = new Point(0, -Size.Height);
          break;
        case EnumRelativePositionType.Under:
          result = new Point(0, _control.Size.Height);
          break;
        case EnumRelativePositionType.Center:
          result = new Point(_control.Size.Width / 2, _control.Size.Height / 2);
          break;
        default:
          break;
      }
      return result;
    }


    public new void ShowToolTip()
    {
      _strControlName = _control.Name;
      IWin32Window window = new WindowWrapper(_control.Handle);
      Show(window);

    }

    private void setLocation()
    {
      Point ptReferenceLocation = calculateReferenceLocation();
      ptReferenceLocation = _control.PointToScreen(ptReferenceLocation);
      this.Location = Point.Add(ptReferenceLocation, new Size(_ptRelativePosition));
    }

    private void InitializeComponent()
    {
      this.components = new System.ComponentModel.Container();
      this._contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
      this.hideToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
      this.hideAllChildrenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
      this._contextMenuStrip.SuspendLayout();
      this.SuspendLayout();
      // 
      // _contextMenuStrip
      // 
      this._contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
            this.hideToolStripMenuItem,
            this.hideAllChildrenToolStripMenuItem});
      this._contextMenuStrip.Name = "_contextMenuStrip";
      this._contextMenuStrip.Size = new System.Drawing.Size(163, 48);
      // 
      // hideToolStripMenuItem
      // 
      this.hideToolStripMenuItem.Name = "hideToolStripMenuItem";
      this.hideToolStripMenuItem.Size = new System.Drawing.Size(162, 22);
      this.hideToolStripMenuItem.Text = "Hide";
      this.hideToolStripMenuItem.Click += new System.EventHandler(this.hideToolStripMenuItem_Click);
      // 
      // hideAllChildrenToolStripMenuItem
      // 
      this.hideAllChildrenToolStripMenuItem.Name = "hideAllChildrenToolStripMenuItem";
      this.hideAllChildrenToolStripMenuItem.Size = new System.Drawing.Size(162, 22);
      this.hideAllChildrenToolStripMenuItem.Text = "Hide All children";
      this.hideAllChildrenToolStripMenuItem.Click += new System.EventHandler(this.hideAllChildrenToolStripMenuItem_Click);
      // 
      // DocToolTip
      // 
      this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
      this.ClientSize = new System.Drawing.Size(123, 32);
      this.ContextMenuStrip = this._contextMenuStrip;
      this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
      this.Name = "DocToolTip";
      this.Opacity = 0.65;
      this.ShowIcon = false;
      this.ShowInTaskbar = false;
      this.TopMost = true;
      this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DocToolTip_MouseDown);
      this._contextMenuStrip.ResumeLayout(false);
      this.ResumeLayout(false);

    }

    //const and dll functions for moving form
    public const int WM_NCLBUTTONDOWN = 0xA1;
    public const int HT_CAPTION = 0x2;

    [DllImportAttribute("user32.dll")]
    public static extern int SendMessage(IntPtr hWnd,
      int Msg, int wParam, int lParam);

    [DllImportAttribute("user32.dll")]
    public static extern bool ReleaseCapture();

    //call functions to move the form in your form's MouseDown event
    private void DocToolTip_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
    {
      if (e.Button == MouseButtons.Left)
      {
        ReleaseCapture();
        SendMessage(Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
      }
    }




    private string getCaption()
    {
      string strLabel = string.Empty;
      switch (_eToolTipCaption)
      {
        case EnumToolTipCaption.Name:
          strLabel = string.Format("{0}", _strControlName);
          break;
        case EnumToolTipCaption.Type:
          strLabel = string.Format("{0}", _strControlType);
          break;
        case EnumToolTipCaption.NameType:
          strLabel = string.Format("{0}:{1}", _strControlName, _strControlType);
          break;
        case EnumToolTipCaption.Custom:
          strLabel = _strCustomCaption.Replace("%Name%", _strControlName);
          strLabel = strLabel.Replace("%Type%", _strControlType);
          break;
      }

      return strLabel;
    }



    private Point centerLocation()
    {
      Point result = _control.PointToScreen(Point.Empty);
      result.X = _control.Width / 2;
      result.Y = _control.Height / 2;
      return result;
    }


    private void hideToolStripMenuItem_Click(object sender, EventArgs e)
    {
      this.Visible = false;
      _docManager.Refresh();
    }

    private void hideAllChildrenToolStripMenuItem_Click(object sender, EventArgs e)
    {
      setVisibleAllChildren(this, false);
      _docManager.Refresh();
    }

    private void setVisibleAllChildren(DocToolTip dToolTip, bool bVisible)
    {
      foreach (DocToolTip child in dToolTip.Children)
      {
        child.Visible = bVisible;
        setVisibleAllChildren(child, bVisible);
      }

    }



  }
}
